package cn.dev33.satoken.router;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.BackResultException;
import cn.dev33.satoken.exception.StopMatchException;
import cn.dev33.satoken.fun.IsRunFunction;
import cn.dev33.satoken.fun.SaFunction;
import lombok.SneakyThrows;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 路由匹配操作工具类
 *
 * @author kong
 */
public class SaRouter {

    // -------------------- 路由匹配相关 --------------------

    /**
     * 路由匹配
     *
     * @param pattern 路由匹配符
     * @param path    被匹配的路由
     * @return 是否匹配成功
     */
    public static boolean isMatch(String pattern, String path) {
        return SaManager.getSaTokenContext().matchPath(pattern, path);
    }

    /**
     * 路由匹配
     *
     * @param patterns 路由匹配符集合
     * @param path     被匹配的路由
     * @return 是否匹配成功
     */
    public static boolean isMatch(Collection<String> patterns, String path) {
        return patterns.stream().anyMatch(i -> isMatch(i, path));
    }

    /**
     * 路由匹配 (使用当前URI)
     *
     * @param pattern 路由匹配符
     * @return 是否匹配成功
     */
    public static boolean isMatchCurrURI(String pattern) {
        return isMatch(pattern, SaHolder.getRequest().getRequestPath());
    }

    /**
     * 路由匹配 (使用当前URI)
     *
     * @param patterns 路由匹配符集合
     * @return 是否匹配成功
     */
    public static boolean isMatchCurrURI(Collection<String> patterns) {
        return isMatch(patterns, SaHolder.getRequest().getRequestPath());
    }


    // -------------------- 执行相关 --------------------

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param pattern  路由匹配符
     * @param function 要执行的方法
     */
    public static void match(String pattern, SaFunction function) {
        if (isMatchCurrURI(pattern)) {
            function.run();
        }
    }

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param pattern  路由匹配符
     * @param function 要执行的方法
     */
    @SneakyThrows
    public static void match(String pattern, Supplier<Exception> function) {
        if (isMatchCurrURI(pattern)) {
            throw function.get();
        }
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param pattern        路由匹配符
     * @param excludePattern 要排除的路由匹配符
     * @param function       要执行的方法
     */
    public static void match(String pattern, String excludePattern, SaFunction function) {
        if (isMatchCurrURI(pattern)) {
            if (!isMatchCurrURI(excludePattern)) {
                function.run();
            }
        }
    }

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param patterns 路由匹配符集合
     * @param function 要执行的方法
     */
    public static void match(Collection<String> patterns, SaFunction function) {
        if (isMatchCurrURI(patterns)) {
            function.run();
        }
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param patterns        路由匹配符集合
     * @param excludePatterns 要排除的路由匹配符集合
     * @param function        要执行的方法
     */
    public static void match(Collection<String> patterns, Collection<String> excludePatterns, SaFunction function) {
        match(patterns, excludePatterns, null, function, null);
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param patterns        路由匹配符集合
     * @param excludePatterns 要排除的路由匹配符集合
     * @param function        要执行的方法 包含匹配并且不在过滤匹配中
     * @param before          只要包含匹配集合就执行 最前执行
     * @param after           只要包含匹配集合就执行 最后执行(后执行的参数为 是否执行了授权验证)
     */
    public static void match(Collection<String> patterns, Collection<String> excludePatterns,
                             SaFunction before, SaFunction function, Consumer<Boolean> after) {
        if (isMatchCurrURI(patterns)) {
            if (Objects.nonNull(before)) {
                before.run();
            }
            boolean ext = !isMatchCurrURI(excludePatterns);
            if ((ext)) {
                function.run();
            }
            if (Objects.nonNull(after)) {
                after.accept(ext);
            }
        }
    }

    /**
     * 路由匹配 (并指定排除匹配符)，如果匹配成功则执行认证函数
     *
     * @param patterns        路由匹配符集合
     * @param excludePatterns 要排除的路由匹配符集合
     * @param excludeFunction 不包含的地址函数过滤
     * @param before          只要包含匹配集合就执行 最前执行
     * @param function        要执行的方法 包含匹配并且不在过滤匹配中
     * @param after           只要包含匹配集合就执行 最后执行(后执行的参数为 是否执行了授权验证)
     */
    public static void match2(Collection<String> patterns,
                              Collection<String> excludePatterns,
                              Function<Collection<String>, Boolean> excludeFunction,
                              Consumer<Boolean> before,
                              SaFunction function,
                              Consumer<Boolean> after) {
        if (isMatchCurrURI(patterns)) {
            boolean exclude = excludeFunction.apply(excludePatterns);
            if (Objects.nonNull(before)) {
                before.accept(exclude);
            }
            if ((exclude)) {
                function.run();
            }
            if (Objects.nonNull(after)) {
                after.accept(exclude);
            }
        }
    }

    /**
     * 路由匹配，如果匹配成功则执行认证函数
     *
     * @param patterns 路由匹配符集合
     * @return 匹配结果包装对象
     */
    public static IsRunFunction match(String... patterns) {
        boolean matchResult = isMatch(Arrays.asList(patterns), SaHolder.getRequest().getRequestPath());
        return new IsRunFunction(matchResult);
    }


    // -------------------- 其它操作 --------------------

    /**
     * 停止匹配，跳出函数 (在多个匹配链中一次性跳出Auth函数)
     */
    public static void stop() {
        throw new StopMatchException();
    }

    /**
     * 停止匹配，结束执行，向前端返回结果
     *
     * @param result 要输出的结果
     */
    public static void back(Object result) {
        throw new BackResultException(result);
    }

    /**
     * 停止匹配，结束执行，向前端返回结果
     */
    public static void back() {
        throw new BackResultException("");
    }

}
